package me.zhengjie.modules.system.rest;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import me.zhengjie.config.MiniAppConfig;
import me.zhengjie.domain.Log;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.exception.EntityExistException;
import me.zhengjie.exception.EntityNotFoundException;
import me.zhengjie.modules.security.config.bean.LoginProperties;
import me.zhengjie.modules.security.config.bean.SecurityProperties;
import me.zhengjie.modules.security.security.TokenProvider;
import me.zhengjie.modules.security.service.OnlineUserService;
import me.zhengjie.modules.security.service.dto.JwtUserDto;
import me.zhengjie.modules.system.domain.Dept;
import me.zhengjie.modules.system.domain.Job;
import me.zhengjie.modules.system.domain.Role;
import me.zhengjie.modules.system.domain.User;
import me.zhengjie.modules.system.service.UserService;
import me.zhengjie.modules.system.service.dto.UserDto;
import me.zhengjie.modules.system.service.mapstruct.UserMapper;
import me.zhengjie.modules.wechatuser.domain.WechatUser;
import me.zhengjie.modules.wechatuser.domain.vo.WechatBindPhoneVo;
import me.zhengjie.modules.wechatuser.domain.vo.WechatCodeVo;
import me.zhengjie.modules.wechatuser.domain.vo.WechatLoginVo;
import me.zhengjie.modules.wechatuser.service.WechatUserService;
import me.zhengjie.modules.wechatuser.service.dto.WechatUserDto;
import me.zhengjie.modules.wechatuser.service.mapstruct.WechatUserMapper;
import me.zhengjie.utils.R;
import me.zhengjie.utils.RedisUtils;
import me.zhengjie.utils.SecurityUtils;
import me.zhengjie.utils.StringUtils;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


@Api(tags = "用户：小程序")
@RestController
@RequestMapping(value = "wechat")
@RequiredArgsConstructor
public class WechatController {

    private final PasswordEncoder passwordEncoder;
    private final WechatUserMapper wechatUserMapper;
    private final WechatUserService wechatUserService;
    private final MiniAppConfig miniAppConfig;
    private final UserService userService;
    private final UserMapper userMapper;

    private final SecurityProperties properties;
    private final RedisUtils redisUtils;
    private final OnlineUserService onlineUserService;
    private final TokenProvider tokenProvider;
    private final AuthenticationManagerBuilder authenticationManagerBuilder;
    @Resource
    private LoginProperties loginProperties;



    @ApiOperation("获取用户code创建微信用户")
    @RequestMapping("preLogin")
    @ResponseBody
    public ResponseEntity<Object> preLogin(@RequestBody WechatCodeVo code) throws WxErrorException {
        WxMaService wxMaService = getWxMaService();
        WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code.getCode());
        String openid = sessionInfo.getOpenid();
        String sessionKey = sessionInfo.getSessionKey();
        String unionid = sessionInfo.getUnionid();
        WechatUserDto wechatUserDto = wechatUserService.findByOpenid(openid);
        if (wechatUserDto == null) {
            WechatUser wechatUser = new WechatUser();
            wechatUser.setOpenId(openid);
            wechatUser.setSessionKey(sessionKey);
            wechatUser.setUnionid(unionid);
            wechatUserService.create(wechatUser);
            return new ResponseEntity<>(wechatUser, HttpStatus.OK);
        } else {
            WechatUser wechatUser = wechatUserMapper.toEntity(wechatUserDto);
            wechatUser.setSessionKey(sessionKey);
            wechatUserService.update(wechatUser);
            return new ResponseEntity<>(wechatUser, HttpStatus.OK);
        }
    }

    @RequestMapping("login")
    @ResponseBody
    @ApiOperation("授权获取用户信息")
    public ResponseEntity<Object> login(@RequestBody WechatLoginVo loginVo , HttpServletRequest request) {
        WxMaService wxMaService = getWxMaService();
        WechatLoginVo.UserInfo userInfo = loginVo.getUserInfo();
        WechatUserDto wechatUserDto = null;
        if (loginVo.getId() != null) { // 根据id 查找用户微信信息 并登录
            wechatUserDto = wechatUserService.findById(loginVo.getId());
        } else if (StringUtils.isNotBlank(loginVo.getOpenId())) {// 根据openid 查找用户微信信息 并登录
            wechatUserDto = wechatUserService.findByOpenid(loginVo.getOpenId());
        } else {
            throw new BadRequestException("请求参数有误！");
        }
        if (wechatUserDto == null) {
            throw new EntityNotFoundException(WechatUserDto.class, "openId", loginVo.getOpenId());
        }
        // 用户信息校验
        if (!wxMaService.getUserService().checkUserInfo(wechatUserDto.getSessionKey(), loginVo.getRawData(), loginVo.getSignature())) {
            throw new BadRequestException("用户信息核验失败");
        }
        WechatUser wechatUser = wechatUserMapper.toEntity(wechatUserDto);
        WxMaUserInfo encryptUserinfo = wxMaService.getUserService().getUserInfo(wechatUserDto.getSessionKey(), loginVo.getEncryptedData(), loginVo.getIv());
        copyProperties(encryptUserinfo, wechatUser);
//        wechatUserService.update(wechatUser);

        User user ;
        if (StringUtils.isBlank(wechatUser.getUserId())){
             user = getUserByWechatUser(wechatUser);
            user = userService.create(user);

            wechatUser.setUserId(user.getId());
            wechatUserService.update(wechatUser);
        }else{
            user= userMapper.toEntity(userService.findByName(wechatUser.getOpenId()));
        }

        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken( user.getUsername()  , "qwer1234!@#$");



        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // 生成令牌
        String token = tokenProvider.createToken(authentication);
        final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal();
        // 保存在线信息
        onlineUserService.save(jwtUserDto, token, request);
        UserDto userSend = jwtUserDto.getUser();
        userSend.setPhone(userSend.getPhone().replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));

        // 返回 token 与 用户信息
        Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
            put("token", properties.getTokenStartWith() + token);
//            put("user", jwtUserDto);
            put("user",userSend);
        }};
        if (loginProperties.isSingleLogin()) {
            //踢掉之前已经登录的token
            onlineUserService.checkLoginOnUser(user.getUsername(), token);
        }

        return new ResponseEntity<>(authInfo, HttpStatus.OK);
    }


    @RequestMapping("bindPhone")
    @ResponseBody
    @ApiOperation("授权绑定用户手机号")
    public ResponseEntity<Object> bindPhone( @Validated  @RequestBody WechatBindPhoneVo wechatBindPhoneVo){
        String id = SecurityUtils.getCurrentUserId();
        UserDto userDto = userService.findById(id);
        if (userDto==null || !userDto.getEnabled()){
            throw new BadRequestException("用户状态异常！");
        }
        WechatUserDto wechatUserDto = wechatUserService.findByUserId(id);
        String sessionKey = wechatUserDto.getSessionKey();
        WxMaService wxMaService = getWxMaService();
        WxMaPhoneNumberInfo phoneNoInfo = wxMaService.getUserService().getPhoneNoInfo(sessionKey, wechatBindPhoneVo.getEncryptedData(), wechatBindPhoneVo.getIv());
        wechatUserDto.setPhone(phoneNoInfo.getPhoneNumber());
        wechatUserService.update(wechatUserMapper.toEntity(wechatUserDto));
        userDto.setPhone(phoneNoInfo.getPhoneNumber());
        userService.update(userMapper.toEntity(userDto));
        User user = userMapper.toEntity(userDto);
        user.setPhone(user.getPhone().replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
        return new ResponseEntity<>( user ,HttpStatus.OK);
    }










    private User getUserByWechatUser(WechatUser wechatUser) {
        User user = new User();
        user.setAvatarName(wechatUser.getAvatarurl());
        user.setAvatarPath(wechatUser.getAvatarurl());
        user.setGender(wechatUser.getGender()==0?"未知":wechatUser.getGender()==1?"男":"女");
        user.setEnabled(true);
        if (StringUtils.isNoneBlank(wechatUser.getPhone())){
            user.setUsername(wechatUser.getPhone());
        }else{
            user.setUsername(wechatUser.getOpenId());
        }
        Dept dept = new Dept();
        dept.setId(16l);
        user.setDept(dept);
        user.setIsAdmin(false);
        user.setNickName(wechatUser.getNickName());
        user.setPhone(wechatUser.getPhone());
        user.setPassword(passwordEncoder.encode("qwer1234!@#$"));

        Set<Role>roles = new HashSet<>();
        Role role = new Role();
        role.setId(5l);
        roles.add(role);
        user.setRoles(roles);

        Set<Job> jobs = new HashSet<>();
        Job job = new Job();
        job.setId(13l);
        jobs.add(job);
        user.setJobs(jobs);

        return user;
    }

    private void copyProperties(WxMaUserInfo wxMaUserInfo, WechatUser wechatUserDto) {
        wechatUserDto.setAvatarurl(wxMaUserInfo.getAvatarUrl());
        wechatUserDto.setProvince(wxMaUserInfo.getProvince());
        wechatUserDto.setCity(wxMaUserInfo.getCity());
        wechatUserDto.setCountry(wxMaUserInfo.getCountry());
        if (StringUtils.isNumeric(wxMaUserInfo.getGender())) {
            wechatUserDto.setGender(Integer.parseInt(wxMaUserInfo.getGender()));
        }
        wechatUserDto.setLanguage(wxMaUserInfo.getLanguage());
        wechatUserDto.setNickName(wxMaUserInfo.getNickName());
    }


    /**
     * 根据配置文件内容得到 WxMaService 服务
     *
     * @return
     */
    private WxMaService getWxMaService() {
        WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
        config.setAppid(miniAppConfig.getAppid());
        config.setSecret(miniAppConfig.getSecret());
        config.setToken(miniAppConfig.getToken());
        config.setAesKey(miniAppConfig.getAesKey());
        config.setMsgDataFormat(miniAppConfig.getMsgDataFormat());
        // 根据配置生成服务
        WxMaService service = new WxMaServiceImpl();
        service.setWxMaConfig(config);
        return service;
    }

}
